// 4、理解了依赖与数据劫持的两大核心概念，现在可以动手尝试组装实现简单的响应式函数方法了

import {
    log
} from "./playground.js";


// ----->这是来自模块2的部分
const targetMap = new WeakMap(); // 全局映射：响应式对象--->属性依赖集合
function track(targetMap, target, key) {
    let depMap = targetMap.get(target); // 哈希表(集合)： 属性--->依赖队列
    if (!depMap) {
        depMap = new Map();
        targetMap.set(target, depMap);
    }
    let dep = depMap.get(key); // 依赖队列
    if (!dep) {
        dep = new Set();
        depMap.set(key, dep);
    }
    dep.add(effect) // 添加进需要依赖的函数，源码中为effect
}
function trigger(targetMap, target, key) {
    const depMap = targetMap.get(target);
    if (!depMap) return; // 对象不存在依赖集合就直接返回
    const dep = depMap.get(key);
    if (dep) {
        dep.forEach(effect => {
            effect();
        });
    }
}



// ------>下面开始的是模块4的部分
// 声明代理对象描述符
const handler = {
    get(target, key, receiver) {
        let res = Reflect.get(target, key, receiver);
        track(targetMap, target, key); // 注意：在这里收集追踪依赖！！
        return res;
    },
    set(target, key, value, receiver) {
        let previousValue = target[key]; // 旧值
        let res = Reflect.set(target, key, value, receiver);// 注意先后顺序，先反射再检测值是否需要触发更新
        // 当侦听到新值与旧值不等时，触发更新
        if (previousValue !== value) {
            trigger(targetMap, target, key);// 注意：在这里更新收集到的依赖
        }
        return res; // 正常设置反射
    }
};
// 返回响应式代理对象
function reactive(target) {
    return new Proxy(target, handler);
}




// 测试用例4
let goods = {
    price: 10,
    quantity: 5
};
let proxyGoods = reactive(goods);// 现在proxyGoods变成了响应式的对象！
let total = 0;
let effect = () => {
    total = proxyGoods.price * proxyGoods.quantity
};
effect();// 收集到了proxyGoods的依赖
log(total);// 50
proxyGoods.price = 100;
log(total);// 500
proxyGoods.quantity = 10;
log(total);// 1000
proxyGoods.quantity = 20;
log(total); // 2000

// 现在你可以发现数据是响应式的了，
// proxyGoods的属性变化，都将触发依赖函数effect的运行，而且这些操作是自动的